package main

import "fmt"

func main() {
	// 类型后置 --》 Go 的声明方式始终遵循名字在前面，类型在后面的原则，从左往右读
	/* var variable string */

	// 类型声明
	/* type MyInt int64 */

	// 通过类型声明的类型都是新类型，不同的类型无法进行运算，即便基础类型是相同的。
	type MyFloat64 float64 /* 类型声明，创建一个新的数据类型 */

	var f1 MyFloat64
	var f float64
	f1 = 0.2
	f = 0.1
	fmt.Println("类型不同无法相加》》f1 + f", f1, f)
	// 类型转换 --> 在数字的类型转换中，通常建议小转大，而不建议大转小【会导致精度丢失】。
	fmt.Println(float64(f1) + f) // 通过类型转换为同一数据类型后就可以进行相加操作了

	/*
		在使用类型转换时，对于一些类型需要避免歧义，例子如下：
			*Point(p) // 等价于 *(Point(p))
			(*Point)(p)  // 将p转换为类型 *Point
			<-chan int(c)    // 等价于 <-(chan int(c))
			(<-chan int)(c)  // 将c转换为类型  <-chan int
			(func())(x)      // 将x转换为类型 func()
			(func() int)(x)  // 将x转换为类型 func() int
	*/

	// 类型别名 --> 类型别名与类型声明则不同，类型别名仅仅只是一个别名，并不是创建了一个新的类型，简单的例子如下：
	type Int = int /* 类型别名 */
	var a Int = 1
	var b int = 2
	fmt.Println(a + b)

	// 类型断言 --》 类型断言通常用于判断某一接口类型的变量是否属于某一个类型，示例如下
	var b1 int = 1
	var a1 interface{} = b1
	if intVal, ok := a1.(int); ok {
		fmt.Println(intVal)
	} else {
		fmt.Println("error type")
	}

	// 类型判断 --》 在 Go 中，switch语句还支持一种特殊的写法，通过这种写法可以根据不同的case做出不同的逻辑处理，使用的前提是入参必须是接口类型，示例如下：
	var a3 interface{} = 2
	switch a3.(type) {
	case int:
		fmt.Println("int")
	case float64:
		fmt.Println("float")
	case string:
		fmt.Println("string")
	}
}

/*类型别名对于一些特别复杂的类型有很大的用处，例如现在有一个类型map[string]map[string]int，这是一个二维 map，现有一个函数参数是map[string]map[string]int类型，如下*/
func PrintMyMap(mymap map[string]map[string]int) {
	fmt.Println(mymap)
}

// 这种情况下，就没有必要使用类型声明了，因为前者是声明了一个新的类型，无法作为该函数的参数，使用类型别名后的例子如下
type TwoDMap = map[string]map[string]int

func PrintMyMapTow(mymap TwoDMap) {
	fmt.Println(mymap)
}
